package classes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import containers.Page;
import containers.StartContainer;

public class PageRetriever implements Runnable {

	private BlockingQueue<StartContainer> myStartQ; /**Queue for StartUpContainers going from the UI to the PR.*/
	private BlockingQueue<List<URL>> myUrlQ; /**Queue for Urls going from the PP to the PR.*/
	private BlockingQueue<Page> myPageQ; /**Queue for Pages going from the PR to the PP.*/
	private Set<String> myVisitedPages; /**Set for visited pages.*/
	private boolean hasProcessedUI; /**Makes sure that we only wait for the startQueue once.*/
	private int numProcessed; /**Total number of url's processed into page objects.*/
	private boolean okToProcess; /**Boolean control if ok to still process pages (numProcessed <= Test.PROCESS_LIMIT_10.*/
	private boolean shouldStop; /**Outside control variable.*/
	private boolean converted; /**determine whether url from urlQ was successfully converted to url**/
	public PageRetriever(final BlockingQueue<StartContainer> startQ, final BlockingQueue<List<URL>> urlQ, 
			final BlockingQueue<Page> pageQ) {
		myStartQ = startQ;
		myUrlQ = urlQ;
		myPageQ = pageQ;
		myVisitedPages = new HashSet<String>();
		hasProcessedUI = false;
		numProcessed = 0;
		okToProcess = true;
		shouldStop = false;
	}
	
	@Override
	public void run() {
		//initialize test string from incorrect thread handleing.
		StartContainer fromUI = null;
		
		//process the startObj from startQ only once.
		if(!hasProcessedUI) {
			//take from the startQ
			try {
				fromUI = myStartQ.take();
			} catch (InterruptedException e) {}
			
			//process			
			if (myVisitedPages.size() < Test.PROCESS_LIMIT) {
				if (validateURL(fromUI.getSeedURL()) == true && myVisitedPages.add(fromUI.getSeedURL().toString()) == true) {
					Page currPage = convertURLtoPage(fromUI.getSeedURL());
					if (converted) {
						addToPageQueue(currPage);
						numProcessed++;
					}
				}
			}
			
			//change test condition
			hasProcessedUI = true;
		}
		
		//process the URLobjs from the urlQ while available or while under limit.
		while(okToProcess) {
//			take from the urlQ
			List<URL> fromPP = new ArrayList<URL>();
			try {
				fromPP = myUrlQ.take();
			} catch (InterruptedException e) {}
			
			//process
//			for (URL link : fromPP) {
			for (int i = 0; i < fromPP.size() && numProcessed < Test.PROCESS_LIMIT; i++) {
				if (myVisitedPages.size() < Test.PROCESS_LIMIT && !shouldStop) {
					URL link = fromPP.get(i); //had to do this to get rid of ConcurrentModificationException due to .openStream() in convertURLtoPage()
					if (validateURL(link) == true && myVisitedPages.add(link.toString()) == true) {
						Page currPage = convertURLtoPage(link);
						//send page to pageQ
						if (converted) {
							addToPageQueue(currPage);
							numProcessed++;
							System.out.print(".");
						}
					}
				}
			}
						
			//test for stop condition
			if(numProcessed >= Test.PROCESS_LIMIT || shouldStop) {
				okToProcess = false;
				myUrlQ.clear();
			}
		}
	}
	
	private synchronized boolean validateURL(final URL theURL) {
		boolean valid = false;
		String mimeType = new String();
		
		try {
			mimeType = theURL.openConnection().getContentType();
		} catch (IOException e) {
			e.printStackTrace();
		} 
		
		if ( mimeType.equals("text/html") || mimeType.equals("text/plain")) {
			valid = true;
		}
		
		return valid;		
	}
	
	private Page convertURLtoPage(final URL url) {
		String currStringURL = new String();
		Page currPage = new Page(url);
		InputStream iStream = null;
		BufferedReader bReader;
		String myString = "";
		StringBuilder sBuilder = new StringBuilder();
		converted = true;
		
		try {
			currStringURL = url.toString();
			iStream = url.openStream();
			bReader = new BufferedReader(new InputStreamReader(iStream));
			while ((myString = bReader.readLine()) != null) {
				sBuilder.append(myString);
			}
			currPage.buildRetrievedPage(url.toString(), sBuilder.toString());
		} catch (IOException e) {
			converted = false;
		}
		
		return currPage;
	}
	
	private void addToPageQueue(final Page currPage) {
		try {
			myPageQ.put(currPage);
		} catch (InterruptedException e) {}
	}
	
	public void stop() {
		shouldStop = true;
	}
}
